import {
  Shape,
  Mesh,
  Object3D,
  ExtrudeGeometry,
  MeshStandardMaterial,
  Color,
  DoubleSide,
  Vector3,
  Line,
  BufferGeometry,
  LineBasicMaterial,
  TextureLoader,
  SpriteMaterial,
  Box3,
  Raycaster,
  Sprite,
  Vector2
} from 'three'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js'
import * as d3 from 'd3'
import { camera } from './ThreeEngine'

const offsetXY = d3.geoMercator()
const createMesh = (data, color, depth, name) => {
  const shape = new Shape()
  data.forEach((item, idx) => {
    const [x, y] = offsetXY(item)

    if (idx === 0) shape.moveTo(x, -y)
    else shape.lineTo(x, -y)
  })

  const extrudeSettings = {
    depth: depth,
    bevelEnabled: false
  }
  const materialSettings = {
    color: color,
    emissive: 0x000000,
    roughness: 0.45,
    metalness: 0.8,
    transparent: true,
    side: DoubleSide
  }
  const geometry = new ExtrudeGeometry(shape, extrudeSettings)
  const material = new MeshStandardMaterial(materialSettings)
  const mesh = new Mesh(geometry, material)
  if (name) {
    mesh.name = name
    mesh.userData.clickable = true
  }
  return mesh
}
const createLine = (data, depth) => {
  const points = []
  data.forEach((item) => {
    const [x, y] = offsetXY(item)
    points.push(new Vector3(x, -y, 0))
  })
  const lineGeometry = new BufferGeometry().setFromPoints(points)
  const uplineMaterial = new LineBasicMaterial({ color: 0xffffff })
  const downlineMaterial = new LineBasicMaterial({ color: 0xffffff })

  const upLine = new Line(lineGeometry, uplineMaterial)
  const downLine = new Line(lineGeometry, downlineMaterial)
  downLine.position.z = -0.0001
  upLine.position.z = depth + 0.0001
  return [upLine, downLine]
}
const createLabel = (name, point, depth) => {
  const div = document.createElement('div')
  div.style.color = '#fff'
  div.style.fontSize = '12px'
  div.style.textShadow = '1px 1px 2px #047cd6'
  div.textContent = name
  const label = new CSS2DObject(div)
  label.scale.set(0.01, 0.01, 0.01)
  const [x, y] = offsetXY(point)
  label.position.set(x, -y, depth)
  return label
}
const createIcon = (point, depth) => {
  const url = new URL('../assets/icon.png', import.meta.url).href
  const map = new TextureLoader().load(url)
  const material = new SpriteMaterial({
    map: map,
    transparent: true
  })
  const sprite = new Sprite(material)
  const [x, y] = offsetXY(point)
  sprite.scale.set(0.3, 0.3, 0.3)

  sprite.position.set(x, -y, depth + 0.2)
  sprite.renderOrder = 1

  return sprite
}
const setCenter = (map) => {
  map.rotation.x = -Math.PI / 2
  const box = new Box3().setFromObject(map)
  const center = box.getCenter(new Vector3())

  const offset = [0, 0]
  map.position.x = map.position.x - center.x - offset[0]
  map.position.z = map.position.z - center.z - offset[1]
}
export const createMap = (data) => {
  const map = new Object3D()
  const center = data.features[0].properties.centroid
  offsetXY.center(center).translate([0, 0])
  data.features.forEach((feature) => {
    const unit = new Object3D()
    const { centroid, center, name } = feature.properties
    const { coordinates, type } = feature.geometry
    const point = centroid || center || [0, 0]

    const color = new Color(`hsl(
        ${213},
        ${Math.random() * 30 + 55}%,
        ${Math.random() * 30 + 55}%)`).getHex()
    const depth = 10

    const label = createLabel(name, point, depth)
    console.log(point);
    // const icon = createIcon(center, depth)

    coordinates.forEach((coordinate) => {
      if (type === 'MultiPolygon') coordinate.forEach((item) => fn(item))
      if (type === 'Polygon') fn(coordinate)

      function fn(coordinate) {
        unit.name = name
        const mesh = createMesh(coordinate, color, depth, name)

        unit.add(mesh)
        
        const line = createLine(coordinate, depth)
        // unit.add(mesh)
      }
    })
    map.add(unit, label)
    setCenter(map)
  })
  return map
}
